
#ifndef _MEMBER_BSCENE_H_
#define _MEMBER_BSCENE_H_

#include <BMap>
#include <BEvent>
#include <BScene>
#include <BOctTree>
#include <BFixedRestraint>
#include "IBroadphase.h"
#include "member_BSoftBody.h"

#define scene_member(scene)		((member_BScene*)((BScene*)scene)->_ptr)

namespace BWE
{
	struct ShapeInfo
	{
		BNode* node = 0;
		BShape* shape = 0;
		BSpace space;
	};
	typedef BArray<ShapeInfo>		ShapeInfoArray;
	typedef BMap<BReal, ShapeInfo>	ShapeInfoQueue;

	struct SceneSet
	{
		BArray<BShapeHolder>	shapes;
		BArray<BNodeHolder>		nodes;
		BArray<BBody*>			bodies;
		BArray<BLight*>			lights;
		BArray<BCamera*>		cameras;
	};
	typedef BOctTree<SceneSet>				SceneOctTree;
	typedef SceneOctTree::Item				SceneOctTreeItem;
	typedef SceneOctTree::ItemArray			SceneOctTreeItemArray;
	typedef SceneOctTree::ConstItemArray	ConstSceneOctTreeItemArray;

	class member_BScene : public BObject
	{
		friend class BScene;
	public:
		member_BScene(BScene* scene);
		~member_BScene();

		void update(BReal time);
		void updateGroup(BGroup* group, BReal time);

		void freshOctTree();
		void freshGroupOctTree(BGroup* group);

		void collectShapes(SceneOctTreeItem& item, BShapeArray& shapes);
		void collectNodes(SceneOctTreeItem& item, BNodeArray& nodes);
		void collectBodies(SceneOctTreeItem& item, BBodyArray& bodies);
		void collectLights(SceneOctTreeItem& item, BLightArray& lights);
		void collectCameras(SceneOctTreeItem& item, BCameraArray& cameras);

		void attachGroup(BGroup* group);
		void detachGroup(BGroup* group);

		IAlgorithm* createAlgorithm(BShape* shape0, BShape* shape1);

		void stepSimulation(BReal timeStep);
		void selectRestraints(BGroup* group);
		void solveRestraints(BReal stepTime);
		bool needsCollision(const BBody* bodyA, const BBody* bodyB);

	protected:
		void prepareFixedRestraints();
		void updateFixedInfo(BSolverItem& item);
		void setupRestraint(BSolverItem* items, int solverSize, BRestraint* restraint, BReal stepTime);
		void setupContact(BContact& contact, const BReal stepTime);
		void addFrictionRestraint(BContact& contact, const BVector& normalAxis, int contactIndex, const BVector& pointA, const BVector& pointB, BReal stepTime);
		void addRollingFrictionRestraint(BContact& contact, const BVector& normalAxis, int contactIndex);

		BReal solveSingleRestraint(BSolverItem& item);
		BReal solveSinglePenetration(BSolverItem& item);

	public:
		void slotShapeFreshed(BShape* shape);
		void slotShapeDirty(BShape* shape);
		void slotShapeTransformed(BShape* shape);

		void slotNodeFreshed(BNode* node);
		void slotNodeDirty(BNode* node);
		void slotNodeInsert(BNode* node, const BValue& value);
		void slotNodeRemove(BNode* node, const BValue& value);
		void slotNodeTransformed(BNode* node);

		void slotGroupFreshed(BGroup* group);
		void slotGroupDirty(BGroup* group);
		void slotGroupInsert(BGroup* group, const BValue& value);
		void slotGroupRemove(BGroup* group, const BValue& value);

		BScene*					boss;
		bool					refresh;
		bool					dirtySpace;
		BSpace					space;
		BSet<BShapeHolder>		shapes;
		BSet<BNodeHolder>		nodes;
		BSet<BGroupHolder>		groups;
		BSet<BRestraintHolder>	restraints;
		BSet<BLight*>			lights;
		BSet<BCamera*>			cameras;
		BSet<BBody*>			bodies;
		BSet<BSoftBody*>		softBodies;
		BSet<BRestraint*>		validRestraints;

		BHolder<SceneOctTree>	sceneOctTree;
		BMap<const BShape*, SceneOctTreeItem> shapeSpaceMap;
		BMap<const BNode*, SceneOctTreeItem> nodeSpaceMap;

		struct FixedInfo
		{
			BReal		mass;
			BReal		invMass;
			BVector		inertia;
			BVector		invInertia;
		};

		BReal				fixedStep;
		bool				paused;
		BReal				tick;
		BReal				totalTime;
		ISoftInfo			softInfo;
		IBroadphase			broadphase;
		BArray<IAlgorithmHolder>	algorithms;
		BArray<BContact>		contacts;
		BMap<BBody*, FixedInfo>	fixedInfoMap;
		BArray<BSolverItem>		restraintSolverItems;
		BArray<BSolverItem>		contactSolverItems;
		BArray<BSolverItem>		frictionSolverItems;
		BArray<BSolverItem>		rollingFrictionSolverItems;

	};
}
#endif
